//////////////////////////////////////////////////////////////////////////

#ifndef _BUFFERTEST_H_
#include "buffertest.h"
#endif

//////////////////////////////////////////////////////////////////////////

#ifndef _BUFFER_H_
#include "buffer.h"
#endif

#include <iostream>
#include <cassert>

//////////////////////////////////////////////////////////////////////////


/** Empty buffer test */
void TestEmptyBuffer();


/** Simple buffer test */
void TestSimpleBuffer();


/** Overflowed buffer test */
void TestOverFlowedBuffer();


/** Output stream and input stream buffer test */
void TestStreamOperations();


/** Custom buffer test */
void TestCustomBuffer( const char* _str, size_t _size, bool _compress = true );


//////////////////////////////////////////////////////////////////////////


void TestBuffer()
{
    try
    {
        // Try several tests
        TestEmptyBuffer();
        TestSimpleBuffer();
        TestOverFlowedBuffer();
        TestStreamOperations();

        // If we are here -- all tests are OK
        std::cout << "Buffer test OK!" << std::endl;
    }

    catch (const char* _str)
    {
        // Test failed -- print why
        std::cout << "Buffer test failed" << std::endl
            << _str << std::endl;
    }
    catch (...)
    {
        // Test failed due to unknown reason
        std::cout << "Buffer test failed" << std::endl;
    }
}


//////////////////////////////////////////////////////////////////////////


void TestEmptyBuffer()
{
    // Test 2 empty buffers
    TestCustomBuffer(NULL, 0);
    TestCustomBuffer(NULL, 500);
}


//////////////////////////////////////////////////////////////////////////


void TestSimpleBuffer()
{
    // Test some buffer
    std::string s( "1234567890 abcdefghigklmnopqrstuvqxyz !@#$%^&*()_+|" );
    TestCustomBuffer( s.c_str(), s.size() );
}


//////////////////////////////////////////////////////////////////////////


void TestOverFlowedBuffer()
{
    const size_t size = 4096;
    char* mem = new char[size];

    // Compression does not work here. I don't know why.
    TestCustomBuffer(mem, size, false);

    delete mem;
}


//////////////////////////////////////////////////////////////////////////


void TestStreamOperations()
{
    Buffer buf;

    // Integers
    int i1(0), i2(12345), i3(-321);
    int i4, i5, i6;

    // Output to buffer
    buf.WriteInt(i1);
    buf.WriteInt(i2);
    buf.WriteInt(i3);

    // Test the buffer
    TestCustomBuffer( buf.Data(), buf.Size() );

    // Input from buffer
    i4 = buf.ReadInt();
    i5 = buf.ReadInt();
    i6 = buf.ReadInt();

    if (i1 != i4 || i2 != i5 || i3 != i6)
        throw( "Buffer << and >> failed with 3 integers test" );

    // Doubles
    double d1(0.0), d2(12345.12345), d3(-321.321);
    double d4, d5, d6;

    // Output to buffer
    buf.WriteDouble(d1);
    buf.WriteDouble(d2);
    buf.WriteDouble(d3);

    // Test the buffer
    TestCustomBuffer( buf.Data(), buf.Size() );

    // Input from buffer
    d4 = buf.ReadDouble();
    d5 = buf.ReadDouble();
    d6 = buf.ReadDouble();

    if (d1 != d4 || d2 != d5 || d3 != d6)
        throw( "Buffer << and >> failed with 3 doubles test" );
}


//////////////////////////////////////////////////////////////////////////


void TestCustomBuffer( const char* _str, size_t _size, bool _compress )
{
    // Create buffers from data
    Buffer buf(_str, _size);
    Buffer buf2;

    // Assign second to first
    buf2 = buf;

    if (buf2 != buf)
        throw( "Buffers are not equal after operator=" );

    // Create 3d buffer from 2nd
    Buffer buf3(buf2);

    if (buf3 != buf2)
        throw( "Buffers are not equal after copy constructor" );

    // Create 4th empty buffer from 3rds data
    Buffer buf4( buf3.Data(), buf3.Size() );

    if (buf3 != buf2)
        throw( "Buffers are not equal after constructor from buffers data" );

    // Get 4th buffer data
    const char* str = buf4.Data();
    size_t size = buf4.Size();

    if (_compress)
    {
        // Create 5th buffer
        Buffer buf5(str, size);

        if (buf5 != buf4)
            throw( "Buffers are not equal after constructor from buffers data" );

        // Compress and decompress the buffer
        buf5.Encode();
        buf5.Decode();

        if (buf5 != buf4)
            throw( "Buffers are not equal after huffman encoding / decoding" );
    }
}


//////////////////////////////////////////////////////////////////////////
